#include "app_buffer.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"



/**
 * @brief 初始化缓冲区结构体
 * @return 缓冲区结构体指针
 * 
 * 1 创建 主缓冲区结构体 
 * 2 创建 子缓冲区结构体 * 2 
 * 
 */
app_buffer_t *app_buffer_init()
{

    // * 1 创建 主缓冲区结构体 
    app_buffer_t *buffer = (app_buffer_t *)malloc(sizeof(app_buffer_t));
    if(buffer==NULL)
    {
        perror("main buffer malloc error");
        return NULL;
    }
   
    // * 2 创建 子缓冲区结构体 * 2 
    for (size_t i = 0; i < 2; i++)
    {
        app_buffer_sub_t *sub_buffer=  (app_buffer_sub_t *)malloc(sizeof(app_buffer_sub_t));   
        sub_buffer->data_len=0;
        sub_buffer->data_ptr=malloc(APP_BUFFER_SIZE);
        sub_buffer->total_len=APP_BUFFER_SIZE;
        buffer->sub_buffers[i]=sub_buffer;
    }
    
    buffer->read_index=0; //0号缓冲负责读 默认
    buffer->write_index=1;//1号缓冲负责写 默认
    //初始化锁
    pthread_mutex_init(&buffer->read_lock,NULL);
    pthread_mutex_init(&buffer->swap_lock,NULL);

    return buffer;

}

/**
 * @brief 读写切换
 */
static void app_buffer_swap(app_buffer_t *buffer)
{
    log_info("app_buffer_swap");
    pthread_mutex_lock(&buffer->swap_lock);
    buffer->read_index=buffer->read_index==0?1:0;
    buffer->write_index=buffer->write_index==0?1:0;
    pthread_mutex_unlock(&buffer->swap_lock);
}


/**
 * @brief 向缓冲区写入数据
 * @param buffer 的结构体指针
 * @param write_data 写入的数据
 * @param write_data_len 写入的数据长度
 * @return 写入成功返回0，失败返回-1
 * 
 * 步骤：
 *  
 * 1 检查  不能超过总空间 且  不能超过127（一个字节的帧头长度）
 * 
 * 2 检查  写缓冲是否还有足够的剩余空间
 * 3 写入数据 
 *    3.1  写入帧头 数据长度 
 *    3.2  写入 数据
 *    3.3  更新长度
 */
int app_buffer_write(app_buffer_t *buffer, char *write_data, int write_data_len)
{

    //A 
    // * 1 检查  不能超过总空间 且  不能超过127（一个字节的帧头长度）
    if(write_data_len>APP_BUFFER_SIZE || write_data_len>127)
    {   
        log_error("超过总空间或者超过127");
        return -1;
    }
    //B 加锁
    pthread_mutex_lock(&buffer->swap_lock);
    //  取出写缓冲区
    app_buffer_sub_t *write_sub_buffer=  buffer->sub_buffers[buffer->write_index];

    // * 2 检查  写缓冲是否还有足够的剩余空间
    // 
    //C 
    int remain_len=write_sub_buffer->total_len-write_sub_buffer->data_len;
    if(remain_len<write_data_len+1)  // 要考虑帧头的空间
    {
        log_error("写缓冲区剩余空间不足");
        return -1;
    }
    // * 3 写入数据 
    // *    3.1  写入帧头 数据长度 
    write_sub_buffer->data_ptr[write_sub_buffer->data_len]=write_data_len;
    // *    3.2  写入 数据
    memcpy(write_sub_buffer->data_ptr+write_sub_buffer->data_len+1,write_data,write_data_len);
    // *    3.3  更新长度
    write_sub_buffer->data_len+=write_data_len+1;
    pthread_mutex_unlock(&buffer->swap_lock);
    return 0;
}


/**
 * @brief 从缓冲区读取数据
 * @param buffer 的结构体指针
 * @param read_buff 读取的数据
 * @param read_buff_len 读取的数据长度
 * @return 读取成功返回 实际读取的大小，失败返回-1
 * 步骤 
 * 1  取出 读缓冲区
 * 2  判断读缓冲区是否为空
 * 3  如果为空
 *         3.1  则进行读写切换
 *         3.2  重新根据读写下标取出读缓冲区
 *         3.3  再判断是否为空  如果为空则 返回 0
 *        
 * 4   如果有数据  取出 帧头数据长度 
 * 5   如果帧头数据长度大于容器长度
 * 6   读取数据 
 *         6.1   把数据读取到read_buff中
 *         6.2   删除已读取的数据
 *         6.3   更新数据长度
 * // 如果数据读取完毕 后发现长度为0 可以进行读写切换(可选)
 * 7   返回 实际读取的大小 
 * 
 */
int app_buffer_read(app_buffer_t *buffer, char *read_buff, int read_buff_len)
{

    //A    加锁 
    pthread_mutex_lock(&buffer->read_lock);
    // * 1  根据下标取出 读缓冲区
    app_buffer_sub_t *read_sub_buffer=  buffer->sub_buffers[buffer->read_index];
    //B
    // * 2  判断读缓冲区是否为空
    if(read_sub_buffer->data_len==0)
    {
            // * 3  如果为空
    // *         3.1  则进行读写切换
               app_buffer_swap(buffer);
    // *         3.2  重新根据读写下标取出读缓冲区
               read_sub_buffer=  buffer->sub_buffers[buffer->read_index];
    // *         3.3  再判断是否为空  如果为空则 返回 0
              if(read_sub_buffer->data_len==0)
              {
                  return 0;
              }
    }
    //C 
    // * 4   如果有数据  取出 帧头数据长度 
    int  read_data_len=read_sub_buffer->data_ptr[0];
    // * 5   如果帧头数据长度大于容器长度
    if(read_data_len> read_buff_len)
    {
        log_error("帧头数据长度大于临时容器长度");
        return -1;
    }
    //D 
    // * 6   读取数据 
    // *         6.1   把数据读取到read_buff中
    memcpy(read_buff,read_sub_buffer->data_ptr+1,read_data_len);
    // *         6.2   删除已读取的数据
    memmove(read_sub_buffer->data_ptr,read_sub_buffer->data_ptr+read_data_len+1,read_sub_buffer->data_len-read_data_len-1);
    // *         6.3   更新数据长度
    read_sub_buffer->data_len-=read_data_len+1;
    // * // 如果数据读取完毕 后发现长度为0 可以进行读写切换(可选)

    pthread_mutex_unlock(&buffer->read_lock);
    // * 7   返回 实际读取的大小 
    return read_data_len;
}



/**
 * @brief 销毁缓冲区结构体
 * @param buffer 缓冲区的结构体指针

 */
void app_buffer_destroy(app_buffer_t *buffer)
{
    for (size_t i = 0; i < 2; i++)
    {
        free(buffer->sub_buffers[i]->data_ptr); //释放子缓冲区数据
        free(buffer->sub_buffers[i]);//释放子缓冲区结构体
    }
    pthread_mutex_destroy(&buffer->read_lock);
    pthread_mutex_destroy(&buffer->swap_lock);
    free(buffer);//释放主缓冲区结构体

}